package com.xu.cloud.common.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * spring ioc容器工具类
 *
 * @author xuguan
 * @since 2023/12/25
 */
@Component
public class ApplicationContextUtil implements BeanFactoryPostProcessor, ApplicationContextAware {

    private static ConfigurableListableBeanFactory beanFactory;
    private static ApplicationContext applicationContext;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        ApplicationContextUtil.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }

    private static ListableBeanFactory getBeanFactory() {
        return Objects.nonNull(applicationContext) ? applicationContext : beanFactory;
    }

    private static ConfigurableListableBeanFactory getConfigurableBeanFactory() {
        if (Objects.nonNull(beanFactory)) {
            return beanFactory;
        } else {
            if (applicationContext instanceof ConfigurableApplicationContext) {
                return ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
            }
        }
        throw new UnsupportedOperationException("can not get ConfigurableListableBeanFactory");
    }

    public static <T> T getBean(String beanName) {
        return (T) getBeanFactory().getBean(beanName);
    }

    public static <T> T getBean(String beanName, Class<T> clazz) {
        return getBeanFactory().getBean(beanName, clazz);
    }

    public static <T> T getBean(Class<T> clazz) {
        return getBeanFactory().getBean(clazz);
    }

    public static <T> void registerBean(String beanName, T bean) {
        getConfigurableBeanFactory().registerSingleton(beanName, bean);
    }

    public static <T> void destroyBean(String beanName) {
        ListableBeanFactory listableBeanFactory = getBeanFactory();
        if (listableBeanFactory instanceof DefaultSingletonBeanRegistry) {
            ((DefaultSingletonBeanRegistry) listableBeanFactory).destroySingleton(beanName);
        }
        throw new UnsupportedOperationException("can not get DefaultSingletonBeanRegistry to destroy Bean");
    }

    public static String getProperty(String key) {
        if (Objects.isNull(applicationContext)) {
            return null;
        }
        return applicationContext.getEnvironment().getProperty(key);
    }

    public static String getProperty(String key, String defaultValue) {
        if (Objects.isNull(applicationContext)) {
            return defaultValue;
        }
        return applicationContext.getEnvironment().getProperty(key, defaultValue);
    }

    public static String resolvePlaceholders(String expression) {
        if (Objects.isNull(applicationContext)) {
            return null;
        }
        return applicationContext.getEnvironment().resolvePlaceholders(expression);
    }

    public static String getActiveProperty() {
        if (Objects.isNull(applicationContext)) {
            return null;
        }
        return applicationContext.getEnvironment().getActiveProfiles()[0];
    }

    public static void publishEvent(ApplicationEvent event) {
        if (Objects.nonNull(applicationContext)) {
            applicationContext.publishEvent(event);
        }
    }
}
